package resolver

import (
	"context"
	"go.etcd.io/etcd/api/v3/mvccpb"
	clientv3 "go.etcd.io/etcd/client/v3"
	"google.golang.org/grpc/grpclog"
	"google.golang.org/grpc/resolver"
	"log"
)

// watcher监听前缀
func (b *builder) watchEtcdService(ctx context.Context, cli *clientv3.Client, prefix string, tgt target) {

	// 初始化服务地址列表
	resp, err := b.etcd.Get(context.Background(), prefix, clientv3.WithPrefix())
	if err != nil {
		grpclog.Errorf("[etcd resolver] Init Service List Failed. target={%s}; error={%v}", tgt.String(), err)

	}
	for _, ev := range resp.Kvs {
		b.SetServiceList(string(ev.Key), string(ev.Value))
	}

	rch := cli.Watch(ctx, prefix, clientv3.WithPrefix())

	for wresp := range rch {
		for _, ev := range wresp.Events {
			switch ev.Type {
			// 新增或修改
			case mvccpb.PUT:
				err := b.SetServiceList(string(ev.Kv.Key), string(ev.Kv.Value))
				if err != nil {
					grpclog.Errorf("[etcd resolver] Set to Service List Failed. target={%s}; error={%v}", tgt.String(), err)
				}
			// 删除
			case mvccpb.DELETE:
				err := b.DelServiceList(string(ev.Kv.Key))
				if err != nil {
					grpclog.Errorf("[etcd resolver] Delete form Service List Failed. target={%s}; error={%v}", tgt.String(), err)
				}
			}
		}
	}
}

// SetServiceList新增服务地址
func (b *builder) SetServiceList(key, val string) error {
	b.serverList.Store(key, resolver.Address{Addr: val})
	err := b.cc.UpdateState(resolver.State{Addresses: b.getServices()})
	if err != nil {
		return err
	}
	log.Println("put key :", key, "val:", val)
	return nil
}

// DelServiceList删除服务地址

func (b *builder) DelServiceList(key string) error {
	b.serverList.Delete(key)
	err := b.cc.UpdateState(resolver.State{Addresses: b.getServices()})
	if err != nil {
		return err
	}
	log.Println("del key:", key)
	return nil
}

// GetServices获取服务地址
func (b *builder) getServices() []resolver.Address {
	addrs := make([]resolver.Address, 0, 10)
	b.serverList.Range(func(k, v interface{}) bool {
		addrs = append(addrs, v.(resolver.Address))
		return true
	})
	// [{localhost:8000  <nil> 0 <nil>}]
	return addrs
}
